/**
 * Copyright [2012-2013] [Guðmundur Björn Birkisson]
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. Copyright [2012-2013] [Guðmundur Björn Birkisson]
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * ---------------------------------------------------------------------------
 * 
 * Class name:  GameController
 * 
 * Description of class:
 * 
 * A static class that Morpho VM calls to control Karel the robot.
 * 
 */
package karel.gamelogic;

import karel.gamelogic.commands.*;
import karel.graphics.Renderer;

public class GameController {

    private static volatile Renderer renderer;
    private static volatile GameContainer game;
    private static GameCommandThread cmdThread;
    private static boolean hasGameContainer = false;

    public static synchronized void setRenderer(Renderer newRenderer) {
        renderer = newRenderer;
    }

    public static synchronized void setGameContainer(GameContainer gameCont) {
        hasGameContainer = gameCont != null;
        if (cmdThread == null || !cmdThread.isAlive()) {
            game = gameCont;
            renderer.setGameContainer(game);
            renderer.componentResized(null);
        }
    }
    
    public static synchronized GameContainer getGameContainer() {
        return game;
    }
    
    public static synchronized boolean hasGameContainer() {
        return hasGameContainer;
    }

    public static synchronized void resetGameContainer() {
        if (cmdThread == null || !cmdThread.isAlive()) {
            game.resetGameContainer();
            renderer.repaintScene();
        }
    }

    public static synchronized void killCommandThread() {
        if (cmdThread != null) {
            cmdThread.killThread();
        }
    }
    
    public static synchronized void startCommandThread() {
        cmdThread = new GameCommandThread("KarelCommandThread");
        cmdThread.start();
    }

    private static synchronized Object issueKarelCommand(KarelCommand command) {
        //java.lang.reflect.InvocationTargetException
        if (!cmdThread.isAlive()) {
            return null;
        }
        return cmdThread.issueCommand(command);
    }

    //COMMANDS
    public static void karelTurnLeft() {
        issueKarelCommand(new KcTurn(game.robot, renderer, KcTurn.Turn.LEFT));
    }

    public static void karelTurnRight() {
        issueKarelCommand(new KcTurn(game.robot, renderer, KcTurn.Turn.RIGHT));
    }

    public static boolean karelGoForward() {
        if (((Boolean) issueKarelCommand(new KcCanGoForward(game.robot, renderer, game.map, true))).booleanValue()) {
            issueKarelCommand(new KcForward(game.robot, renderer, game.map));
            return true;
        }
        return false;
    }

    public static boolean karelCanGoForward() {
        return ((Boolean) issueKarelCommand(new KcCanGoForward(game.robot, renderer, game.map))).booleanValue();
    }

    public static boolean karelIsOnExit() {
        return ((Boolean) issueKarelCommand(new KcIsOnExit(game.robot, renderer, game.map))).booleanValue();
    }
    
    public static boolean karelIsOnRock() {
        return ((Boolean) issueKarelCommand(new KcIsOnRock(game.robot, renderer, game.map))).booleanValue();
    }
    
    public static double karelPickUpRock() {
        return (Double)issueKarelCommand(new KcPickUpRock(game.robot, renderer, game.map));
    }
    
    public static void karelPutDownRock() {
        issueKarelCommand(new KcPutDownRock(game.robot, renderer, game.map));
    }
    
    public static String karelDirection() {
        return (String)issueKarelCommand(new KcDirection(game.robot, renderer));
    }
    
    public static String karelPosition() {
        return (String)issueKarelCommand(new KcPosition(game.robot, renderer));
    }
    
    public static double karelPosX() {
        String res = (String)issueKarelCommand(new KcPosition(game.robot, renderer));
        return Double.parseDouble(res.split(",")[0].replace("(", ""));
    }
    
    public static double karelPosY() {
        String res = (String)issueKarelCommand(new KcPosition(game.robot, renderer));
        return Double.parseDouble(res.split(",")[1].replace(")", ""));
    }
}
